
#include "server.h"
#include "manager.h"
#include "adm.h"

void rp_rstatd_server_init(int argc, char * argv [ ])
{
	char fname[] = "rp_rstatd_server_init";
	char msg[] = "fatal error";
	Err err;
	
	err = rp_rstatd_getopt(argc, argv);
	err = rp_daemonize();
	rp_rstatd_env_init();
	rp_rstatd_config_init();	
	rp_rstatd_global_init();
	rp_rstatd_log_init();
	FLOG_IN(fname);
	
	signal(SIGPIPE, SIG_IGN);
	signal(SIGCHLD, SIG_IGN);
	
	/*	register heartbeat handler	*/
	global.evb_server = event_init();
	evtimer_set(&global.ev_hb, rp_rstatd_manager, NULL);
	event_base_set(global.evb_server, &global.ev_hb);
	if (evtimer_add(&global.ev_hb, &config.tv_heartbeat) < 0)
	{
		rp_log(LOG_FATAL, fname, "Adding timer event failed");
		exit(127);
	}
	
	/* connect with rindexd */ 
	if (rp_comm_tcp_client_init(&global.fd_rindexd, &config.addr_rindexd, COMM_NONBLOCK) != E_OK)
	{
		rp_log(LOG_FATAL, fname, "Cannot connect to Rindexd at %s:%d");	// ip:port
		exit(127);
	}
	event_set(&global.ev_adm, global.fd_rindexd, EV_READ|EV_PERSIST, rp_rstatd_adm, NULL);
	event_base_set(global.evb_server, &global.ev_adm);
	if (event_add(&global.ev_adm, NULL) < 0)
	{
		rp_log(LOG_FATAL, fname, "Adding command event failed");
		exit(127);
	}
	
	/*	create PoD pipe    */
	if (pipe(global.fd_pod) < 0) 
	{
		rp_log(LOG_FATAL, fname, "Cannot create new pipe.");
		exit(127);	
	}
	
	/*	start rpointd pool   */
	int mapfd;
	char tmpfile[MAX_FILENAME_LENGTH];
	char exefile[MAX_FILENAME_LENGTH];
	Worker *pworker;
	struct stat tmpstat;
	
	if (stat("/tmp/rally", &tmpstat) < 0) 
	{
		rp_log(LOG_DEBUG, fname, "/tmp/rally does not exist. we are going to create ...");
		if (mkdir("/tmp/rally", 00777) < 0)
		{
			rp_log(LOG_FATAL, fname, "Cannot create /tmp/rally. Error: %s", strerror(errno));
			exit(127);
		}
	}
	memset(exefile, 0, MAX_FILENAME_LENGTH);
	sprintf(exefile, "%s/rpointd", env.bindir);
	
	int i;
	for (i=0; i<config.num_child_prefork; i++)
	{
		pworker = (Worker*)malloc(sizeof(Worker));
		pworker->exitFlag = 0;
		
		if ((pworker->pid = rp_process_create_with_pipe(exefile, NULL, environ, global.fd_pod)) < 0)
		{
			free(pworker);
			rp_log(LOG_CRITICAL, fname, "Cannot create new rpointd instance ...");
			continue;
		} 
		
		memset(tmpfile, 0, MAX_FILENAME_LENGTH);	
		sprintf(tmpfile, "/tmp/rally/%d", pworker->pid);
		if ((mapfd= open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 00777)) < 0) 	// Rstatd is rsponsible for create/delete the score file		
		{
			err = rp_process_terminate(pworker->pid, SIGTERM);		// Forceful kill the new rpointd process
			pworker->exitFlag = 1;
			err = rp_score_init_pshared(pworker->score);
			err = rp_rstatd_scoreboard_register(&global.sb_dead, pworker);
			rp_log(LOG_CRITICAL, fname, "Cannot open the file %s", tmpfile);
			continue;
		} 
		lseek(mapfd, sizeof(Score), SEEK_END);
		write(mapfd, "", 1);	// mmap size = Score+1
		if ((pworker->score = mmap(0, sizeof(Score), PROT_READ|PROT_WRITE, MAP_SHARED, mapfd, 0)) == MAP_FAILED)
		{
			close(mapfd);
			err = rp_process_terminate(pworker->pid, SIGTERM);		// Forceful kill the new rpointd process
			pworker->exitFlag = 1;
			err = rp_score_init_pshared(pworker->score);
			err = rp_rstatd_scoreboard_register(&global.sb_dead, pworker);
			rp_log(LOG_CRITICAL, fname, "Failed mmap file under /tmp/rally");
			continue;
		} 
		close(mapfd);	
		err = rp_score_init_pshared(pworker->score);
		err = rp_rstatd_scoreboard_register(&global.sb_live, pworker);		
	}
	
	//close(global.fd_pod[0]);		// parent close the read end of PoD
	FLOG_OUT(fname);
}

void rp_rstatd_server_run()
{
	char fname[] = "rp_rstatd_server_run";
	char msg[] = "fatal error";
	Err err;
	FLOG_IN(fname);
	event_base_dispatch(global.evb_server);
	FLOG_OUT(fname);
}

void rp_rstatd_server_finalize()
{
	char fname[] = "rp_rstatd_server_finalize";
	char msg[] = "fatal error";
	Err err;
	FLOG_IN(fname);
	
	err = rp_rstatd_scoreboard_finalize(&global.sb_live);
	err = rp_rstatd_scoreboard_finalize(&global.sb_dead);
	//err = rp_log_finalize();
	
	FLOG_OUT(fname);
}

int main(int argc, char *argv[])
{
	char fname[] = "main";
	char msg[] = "fatal error";
	Err err;

	rp_rstatd_server_init(argc, argv);
	rp_rstatd_server_run();
	rp_rstatd_server_finalize();

	exit(0);
}


